package main

import (
	"fmt"
	"net"
	"sync"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

const (
	CHUNK       = 512
	FORMAT      = 16 // 对应 pyaudio.paInt16
	CHANNELS    = 1
	RATE        = 16000
	BUFFER_SIZE = CHUNK * FORMAT * CHANNELS / 8
	UDP_PORT_LISTEN    = 8888
	UDP_PORT_SEND      = 9999
)

type audio_data [BUFFER_SIZE]byte

var audio_data_chan_to_web = make(chan audio_data, 1000)
var audio_data_chan_to_udp = make(chan audio_data, 1000)
var websocket_map = sync.Map{}
var udp_map = sync.Map{}

func receiveUDPData(port int) {
	port_str := fmt.Sprintf(":%d", port)
	udp_addr, err := net.ResolveUDPAddr("udp", port_str)
	if err != nil {
		fmt.Println("ResolveUDPAddr failed:", err)
		return
	}
	udp_conn, err := net.ListenUDP("udp", udp_addr)
	if err != nil {
		fmt.Println("ListenUDP failed:", err)
		return
	}
	defer udp_conn.Close()
	buf := make([]byte, BUFFER_SIZE)
	for {
		n, _, err := udp_conn.ReadFromUDP(buf)
		if err != nil {
			fmt.Println("ReadFromUDP failed:", err)
			continue
		}
		if n != BUFFER_SIZE {
			fmt.Println("ReadFromUDP failed: data length not match")
			continue
		}
		var data audio_data
		copy(data[:], buf)
		audio_data_chan_to_web <- data
		audio_data_chan_to_udp <- data
	}
}

func create_websocket_handler(c *gin.Context) {
	upgrader := websocket.Upgrader{
		ReadBufferSize:  BUFFER_SIZE * 4, // 4倍于BUFFER_SIZE
		WriteBufferSize: BUFFER_SIZE * 4, // 4倍于BUFFER_SIZE
	}
	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Println("Upgrade failed:", err)
		return
	}
	websocket_map.Store(ws, struct{}{})
	go func() {
		for {
			_, data, err := ws.ReadMessage()
			// fmt.Println(data)
			if err != nil {
				fmt.Println("ws close")
				ws.Close()
				websocket_map.Delete(ws)
				return
			}
			var data_audio audio_data
			copy(data_audio[:], data)
			audio_data_chan_to_web <- data_audio
			audio_data_chan_to_udp <- data_audio
			// fmt.Println(data_audio)
		}
	}()
}
func send_audio_data_to_websocket() {
	for {
		data := <-audio_data_chan_to_web
		websocket_map.Range(func(key, value interface{}) bool {
			ws := key.(*websocket.Conn)
			ws.WriteMessage(websocket.BinaryMessage, data[:])
			return true
		})
	}
}
func send_audio_data_to_udp() {
	udp_addr, err := net.ResolveUDPAddr("udp", "192.168.1.142:"+fmt.Sprintf("%d", UDP_PORT_SEND))
	if err != nil {
		panic(err)
	}
	conn, err := net.DialUDP("udp", nil, udp_addr)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	for {

		data := <-audio_data_chan_to_udp
		// fmt.Println(data)
		conn.Write(data[:])
	}
}
func main() {
	r := gin.Default()
	r.Static("/htmls", "./")
	r.GET("/ws", create_websocket_handler)
	go receiveUDPData(UDP_PORT_LISTEN)
	go send_audio_data_to_websocket()
	go send_audio_data_to_udp()
	// go receivewebsocketData()
	err := r.RunTLS(":8080", "server.crt", "server.key")
	if err != nil {
		fmt.Println("RunTLS failed:", err)
	}
	// r.Run(":8080")
}
